﻿using StackExchange.Redis;
using System;
using System.Threading.Tasks;

public class RedisHelper : IDisposable
{
    private static readonly Lazy<ConnectionMultiplexer> LazyConnection;
    private static ConfigurationOptions _connectionOptions;

    public static event Action<string> ConnectionFailed;
    public static event Action<string> ConnectionRestored;

    static RedisHelper()
    {
        LazyConnection = new Lazy<ConnectionMultiplexer>(() =>
        {
            var connection = ConnectionMultiplexer.Connect(_connectionOptions);

            // 注册连接事件
            connection.ConnectionFailed += (sender, args) =>
                ConnectionFailed?.Invoke($"Connection failed: {args.FailureType}");

            connection.ConnectionRestored += (sender, args) =>
                ConnectionRestored?.Invoke("Connection restored");

            return connection;
        });
    }

    /// <summary>
    /// 初始化Redis连接配置
    /// </summary>
    /// <param name="connectionString">Redis连接字符串</param>
    public static void Initialize(string connectionString)
    {
        _connectionOptions = ConfigurationOptions.Parse(connectionString);
        _connectionOptions.AbortOnConnectFail = false;
        _connectionOptions.ReconnectRetryPolicy = new ExponentialRetry(5000);
        _connectionOptions.ConnectTimeout = 5000;

        // 强制初始化连接
        var _ = Connection;
    }

    /// <summary>
    /// 获取Redis连接实例
    /// </summary>
    public static ConnectionMultiplexer Connection => LazyConnection.Value;

    /// <summary>
    /// 获取数据库实例
    /// </summary>
    public static IDatabase Database => Connection.GetDatabase();

    /// <summary>
    /// 获取订阅器实例
    /// </summary>
    public static ISubscriber Subscriber => Connection.GetSubscriber();

    /// <summary>
    /// 当前连接状态
    /// </summary>
    public static bool IsConnected => Connection.IsConnected;

    /// <summary>
    /// 字符串读取
    /// </summary>
    public static string GetString(string key)
    {
        return Database.StringGet(key);
    }

    /// <summary>
    /// 字符串异步读取
    /// </summary>
    public static async Task<string> GetStringAsync(string key)
    {
        return await Database.StringGetAsync(key);
    }

    /// <summary>
    /// 字符串写入
    /// </summary>
    public static bool SetString(string key, string value, TimeSpan? expiry = null)
    {
        return Database.StringSet(key, value, expiry);
    }

    /// <summary>
    /// 字符串异步写入
    /// </summary>
    public static async Task<bool> SetStringAsync(string key, string value, TimeSpan? expiry = null)
    {
        return await Database.StringSetAsync(key, value, expiry);
    }

    /// <summary>
    /// 发布消息
    /// </summary>
    public static long Publish(string channel, string message)
    {
        return Subscriber.Publish(channel, message);
    }

    /// <summary>
    /// 异步发布消息
    /// </summary>
    public static async Task<long> PublishAsync(string channel, string message)
    {
        return await Subscriber.PublishAsync(channel, message);
    }

    /// <summary>
    /// 订阅频道
    /// </summary>
    public static void Subscribe(string channel, Action<RedisChannel, RedisValue> handler)
    {
        Subscriber.Subscribe(channel, handler);
    }

    /// <summary>
    /// 异步订阅频道
    /// </summary>
    public static async Task SubscribeAsync(string channel, Action<RedisChannel, RedisValue> handler)
    {
        await Subscriber.SubscribeAsync(channel, handler);
    }

    /// <summary>
    /// 取消订阅
    /// </summary>
    public static void Unsubscribe(string channel)
    {
        Subscriber.Unsubscribe(channel);
    }

    /// <summary>
    /// 异步取消订阅
    /// </summary>
    public static async Task UnsubscribeAsync(string channel)
    {
        await Subscriber.UnsubscribeAsync(channel);
    }

    /// <summary>
    /// 关闭Redis连接
    /// </summary>
    public static void CloseConnection()
    {
        if (LazyConnection.IsValueCreated)
        {
            Connection.Close();
            Connection.Dispose();
        }
    }

    public void Dispose()
    {
        CloseConnection();
    }
}